package com.ceadeal.admin.config.security;

import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 功能描述: 自定义认证过滤器
 * 
 * 作者: Yzw
 * 日期: 2017-03-04 14:43:19
 */
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";

    /** 登录成功后跳转的地址 */
    private String successUrl = "/";

    /** 登录失败后跳转的地址 */
    private String errorUrl = "/login?error";

    /**
     * 功能描述: 功能描述：自定义表单参数的name属性，默认是 j_username 和 j_password  定义登录成功和失败的跳转地址
     * @param
     * @return
     * @throws
     *
     * @author Yzw
     * @date 2017-03-04 14:36:00
     */
    public CustomAuthenticationFilter() {
        super();
        SimpleUrlAuthenticationFailureHandler suafHandler = new SimpleUrlAuthenticationFailureHandler(errorUrl);
        suafHandler.setUseForward(true);
        setAuthenticationFailureHandler(suafHandler);
        // 设置用户名和密码的参数名
        this.setUsernameParameter(USERNAME);
        this.setPasswordParameter(PASSWORD);
        // 验证成功，跳转的页面
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setDefaultTargetUrl(successUrl);
        this.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equals("POST")) {
            request.setAttribute("error", "登录异常，请联系管理员");
            throw new AuthenticationServiceException("Authentication method not supported: "+ request.getMethod());
        }

        //校验验证码是否正确
        String captchaToken = (String) request.getSession().getAttribute("captchaToken");
        String captcha = request.getParameter("captcha");
        if (!captchaToken.toLowerCase().equals(captcha.trim().toLowerCase())) {
            request.setAttribute("error", "验证码错误");
            throw new AuthenticationServiceException("验证码错误");
        }

        //获取登录名和密码
        String username = obtainUsername(request);
        String password = obtainPassword(request);
        if (username == null) {
            username = "";
        }
        if (password == null) {
            password = "";
        }
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            request.setAttribute("error", "用户名或密码不允许为空");
            throw new BadCredentialsException("用户名或密码不允许为空");
        }

        // 实现 Authentication
        UsernamePasswordAuthenticationToken upaToken = new UsernamePasswordAuthenticationToken(username, password);
        // 允许子类设置详细属性
        setDetails(request, upaToken);

        // 运行UserDetailsService的loadUserByUsername 再次封装Authentication
        try {
            return this.getAuthenticationManager().authenticate(upaToken);
        } catch (AuthenticationException e) {
            if (e instanceof InternalAuthenticationServiceException) {
                request.setAttribute("error", "账号不存在");
            } else if (e instanceof DisabledException) {
                request.setAttribute("error", "账号已被禁用");
            } else {
                request.setAttribute("error", "用户名或密码不正确");
            }
            throw new BadCredentialsException("登录认证异常");
        }
    }

    public String getSuccessUrl() {
        return successUrl;
    }

    public void setSuccessUrl(String successUrl) {
        this.successUrl = successUrl;
    }

    public String getErrorUrl() {
        return errorUrl;
    }

    public void setErrorUrl(String errorUrl) {
        this.errorUrl = errorUrl;
    }
}
